#include "wifi_tcp.h"
#include "smart_home_event.h"
#include "smart_home.h"

#include "config_network.h"
#include "lwip/tcp.h"
#include "lwip/ip_addr.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/stats.h"
#include "lwip/inet_chksum.h"

#include "cJSON.h"
#include "cmsis_os2.h"
#include "los_task.h"
#include "ohos_init.h"

int client_fd;

static unsigned int tcp_ConnectFlag = 0; // 定义一个标志变量，用于指示MQTT连接状态
int get_wifi_info(WifiLinkedInfo *info)
{
    int ret = -1;
    int gw, netmask;
    memset(info, 0, sizeof(WifiLinkedInfo));
    unsigned int retry = 15;
    while (retry)
    {
        if (GetLinkedInfo(info) == WIFI_SUCCESS)
        {
            if (info->connState == WIFI_CONNECTED)
            {
                if (info->ipAddress != 0)
                {
                    LZ_HARDWARE_LOGD(LOG_TAG, "rknetwork IP (%s)", inet_ntoa(info->ipAddress));

                    if (WIFI_SUCCESS == GetLocalWifiGw(&gw))
                    {
                        LZ_HARDWARE_LOGD(LOG_TAG, "network GW (%s)", inet_ntoa(gw));
                    }

                    if (WIFI_SUCCESS == GetLocalWifiNetmask(&netmask))
                    {
                        LZ_HARDWARE_LOGD(LOG_TAG, "network NETMASK (%s)", inet_ntoa(netmask));
                    }

                    if (WIFI_SUCCESS == SetLocalWifiGw())
                    {
                        LZ_HARDWARE_LOGD(LOG_TAG, "set network GW");
                    }

                    ret = 0;
                    goto connect_done;
                }
            }
        }
        LOS_Msleep(1000);
        retry--;
    }

connect_done:
    return ret;
}
int tcp_client_init(void)
{
    WifiLinkedInfo info;

    int ret, cnt = 0, count = 0;
    struct sockaddr_in serv_addr;

    char buf[BUFF_LEN];

    while (get_wifi_info(&info) != 0)
        ;
    // 创建套接字
    client_fd = socket(AF_INET, SOCK_STREAM, 0); // AF_INET:IPV4;SOCK_STREAM:TCP
    if (client_fd < 0)
    {
        printf("create socket fail!\n");
        return -1;
    }

    /*设置调用close(socket)后,仍可继续重用该socket。调用close(socket)一般不会立即关闭socket，而经历TIME_WAIT的过程。*/
    int flag = 1;
    ret = setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)); // 设置套接字选项
    if (ret != 0)
    {
        printf("[CommInitTcpServer]setsockopt fail, ret[%d]!\n", ret);
    }

    // 配置服务器连接参数
    memset(&serv_addr, 0, sizeof(serv_addr));            // 清空缓冲区后初始化服务器地址
    serv_addr.sin_family = AF_INET;                      // 使用协议
    serv_addr.sin_addr.s_addr = inet_addr(OC_SERVER_IP); // 服务器IP
    serv_addr.sin_port = htons(SERVER_PORT);             // 服务器端口
    printf("[tcp client] connect:%d<%s:%d>\n", client_fd, inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));

    socklen_t len = sizeof(serv_addr);
    while (connect(client_fd, (struct sockaddr *)&serv_addr, len) < 0) // 尝试连接服务器
    {
        printf("connect server failed...%d\n", ++count);
        lwip_close(client_fd);
        LOS_Msleep(5000);
        client_fd = socket(AF_INET, SOCK_STREAM, 0); // AF_INET:IPV4;SOCK_STREAM:TCP
    }
    printf("[tcp client] connect OK!\n");
    // while (cnt < 5)
    // {
    //     sprintf(buf, "TCP TEST cilent send:%d\n", ++cnt);
    //     count = send(client_fd, buf, strlen(buf), 0); // 发送数据给server
    //     if (count < 0)
    //     {
    //         printf("Failed to send data to server.\n");
    //         printf("send failed: %s\n", strerror(errno));
    //     }
    //     printf("------------------------------------------------------------\n");
    //     printf("[tcp_client_init] send:%s\n", buf);
    //     printf("[tcp_client_init] client sendto msg to server %d,waitting server respond msg!!!\n", count);
    //     printf("[tcp_client_init] client_fd:%d\n", client_fd);
    //     LOS_Msleep(1000);
    //     // count = lwip_write(fd, buf, strlen(buf));                   //发送数据给server
    // }
    memset(buf, 0, BUFF_LEN);

    tcp_ConnectFlag = 1;

    return 0;
}

unsigned int tcp_send_data(tcp_data *iot_data)
{
    char payload[MAX_BUFFER_LENGTH] = {0};
    char str[MAX_STRING_LENGTH] = {0};
    int count = 0;

    if (tcp_ConnectFlag == 0)
    {
        printf("ap not connect\n");
        return;
    }

    // 创建 JSON 对象
    cJSON *root = cJSON_CreateObject();
    if (root != NULL)
    {
        cJSON *serv_arr = cJSON_AddArrayToObject(root, "services");
        cJSON *arr_item = cJSON_CreateObject();
        cJSON_AddStringToObject(arr_item, "service_id", "spaceport");
        cJSON *pro_obj = cJSON_CreateObject();
        cJSON_AddItemToObject(arr_item, "properties", pro_obj);

        memset(str, 0, MAX_BUFFER_LENGTH);
        // 光照强度
        sprintf(str, "%5.2f", iot_data->illumination);
        cJSON_AddStringToObject(pro_obj, "light", str);
        // 温度
        sprintf(str, "%5.2f", iot_data->temperature);
        cJSON_AddStringToObject(pro_obj, "th", str);
        // 湿度
        sprintf(str, "%5.2f", iot_data->humidity);
        cJSON_AddStringToObject(pro_obj, "wet", str);
        // pm值
        sprintf(str, "%5.2f", iot_data->ppm);
        cJSON_AddStringToObject(pro_obj, "poison", str);

        // 电机状态
        if (iot_data->motor_state == true)
        {
            cJSON_AddStringToObject(pro_obj, "motorStatus", "ON");
        }
        else
        {
            cJSON_AddStringToObject(pro_obj, "motorStatus", "OFF");
        }
        // 灯光状态
        if (iot_data->light_state == true)
        {
            cJSON_AddStringToObject(pro_obj, "lightStatus", "ON");
        }
        else
        {
            cJSON_AddStringToObject(pro_obj, "lightStatus", "OFF");
        }
        // 自动状态模式
        if (iot_data->auto_state == true)
        {
            cJSON_AddStringToObject(pro_obj, "autoStatus", "ON");
        }
        else
        {
            cJSON_AddStringToObject(pro_obj, "autoStatus", "OFF");
        }
        // 将服务项添加到服务数组
        cJSON_AddItemToArray(serv_arr, arr_item);
        // 转换 JSON 对象为字符串
        char *palyload_str = cJSON_PrintUnformatted(root);
        strcpy(payload, palyload_str);
        // 释放cJSON对象
        cJSON_free(palyload_str);
        cJSON_Delete(root);
    }
    sprintf(payload, "%s\r\n", payload);
    count = send(client_fd, payload, strlen(payload), 0);
    // count = lwip_write(fd, buf, strlen(buf));
    if (count < 0)
    {
        printf("[tcp_send_data] Failed to send data to server.\n");
        printf("[tcp_send_data] send failed: %s\n", strerror(errno));
        return -1;
    }
    printf("[tcp_send_data] send:%s\n", payload);
    // printf("[tcp_send_data] client sendto msg to server %d,waitting server respond msg!!!\n", count);
    // printf("[tcp_send_data] client_fd:%d\n", client_fd);
    memset(payload, 0, BUFF_LEN);
    return 0;
}

unsigned int tcp_send_alarm(tcp_alarm_t *alarm)
{
    char payload[MAX_BUFFER_LENGTH] = {0};
    char str[MAX_STRING_LENGTH] = {0};
    int count = 0;

    if (tcp_ConnectFlag == 0)
    {
        printf("ap not connect\n");
        return;
    }
    // 创建 JSON 对象
    cJSON *root = cJSON_CreateObject();
    if (root != NULL)
    {
        cJSON *serv_arr = cJSON_AddArrayToObject(root, "alarm");
        cJSON *arr_item = cJSON_CreateObject();
        cJSON_AddStringToObject(arr_item, "service_id", "spaceport");
        cJSON *pro_obj = cJSON_CreateObject();
        cJSON_AddItemToObject(arr_item, "properties", pro_obj);
        memset(str, 0, MAX_BUFFER_LENGTH);
       // 电机状态
        if (alarm->ppm_alarm_state == true)
        {
            cJSON_AddStringToObject(pro_obj, "ppm_alarm", "ON");
        }
        else
        {
            cJSON_AddStringToObject(pro_obj, "ppm_alarm", "OFF");
        }
        // // pm值
        // sprintf(str, "%5.2f", iot_data->ppm);
        // cJSON_AddStringToObject(pro_obj, "poison", str);
        // 将服务项添加到服务数组
        cJSON_AddItemToArray(serv_arr, arr_item);
        // 转换 JSON 对象为字符串
        char *palyload_str = cJSON_PrintUnformatted(root);
        strcpy(payload, palyload_str);
        // 释放cJSON对象
        cJSON_free(palyload_str);
        cJSON_Delete(root);
    }
    sprintf(payload, "%s\r\n", payload);
    count = send(client_fd, payload, strlen(payload), 0);
    // count = lwip_write(fd, buf, strlen(buf));
    if (count < 0)
    {
        printf("[tcp_send_alarm] Failed to send data to server.\n");
        printf("[tcp_send_alarm] send failed: %s\n", strerror(errno));
        return -1;
    }
    printf("[tcp_send_alarm] send:%s\n", payload);
    // printf("[tcp_send_data] client sendto msg to server %d,waitting server respond msg!!!\n", count);
    // printf("[tcp_send_data] client_fd:%d\n", client_fd);
    memset(payload, 0, BUFF_LEN);
    return 0;

    return 0;
}

void set_light_state(cJSON *root)
{
    cJSON *para_obj = NULL;
    cJSON *status_obj = NULL;
    char *value = NULL;

    event_info_t event = {0};
    event.event = event_iot_cmd;

    para_obj = cJSON_GetObjectItem(root, "properties");
    status_obj = cJSON_GetObjectItem(para_obj, "onoff");
    if (status_obj != NULL)
    {
        value = cJSON_GetStringValue(status_obj);
        if (!strcmp(value, "ON"))
        {
            event.data.iot_data = IOT_CMD_LIGHT_ON;
            // light_state = true;
        }
        else if (!strcmp(value, "OFF"))
        {
            event.data.iot_data = IOT_CMD_LIGHT_OFF;
            // light_state = false;
        }
        else
        {
            printf("[set_light_state] Missing 'onoff' field in 'properties'!\n");
        }
        smart_home_event_send(&event);
    }
    else
    {
        printf("[set_light_state] Missing 'properties' field in JSON!\n");
    }
}

void set_motor_state(cJSON *root)
{
    cJSON *para_obj = NULL;
    cJSON *status_obj = NULL;
    char *value = NULL;

    event_info_t event = {0};
    event.event = event_iot_cmd;

    para_obj = cJSON_GetObjectItem(root, "properties");
    status_obj = cJSON_GetObjectItem(para_obj, "onoff");
    if (status_obj != NULL)
    {
        value = cJSON_GetStringValue(status_obj);
        if (!strcmp(value, "ON"))
        {
            // motor_state = true;
            event.data.iot_data = IOT_CMD_MOTOR_ON;
        }
        else if (!strcmp(value, "OFF"))
        {
            // motor_state = false;
            event.data.iot_data = IOT_CMD_MOTOR_OFF;
        }
        else
        {
            printf("[set_motor_state] Missing 'onoff' field in 'properties'!\n");
        }
        smart_home_event_send(&event);
    }
    else
    {
        printf("[set_motor_state] Missing 'properties' field in JSON!\n");
    }
}

void set_auto_state(cJSON *root)
{
    cJSON *para_obj = NULL;
    cJSON *status_obj = NULL;
    char *value = NULL;

    para_obj = cJSON_GetObjectItem(root, "properties");
    status_obj = cJSON_GetObjectItem(para_obj, "onoff");
    if (status_obj != NULL)
    {
        value = cJSON_GetStringValue(status_obj);
        if (!strcmp(value, "ON"))
        {
            // printf("auto on\n");
            __set_auto_state(true);
            lcd_set_auto_state(true);
            // auto_state = true;
        }
        else if (!strcmp(value, "OFF"))
        {
            // printf("auto off\n");
            __set_auto_state(false);
            lcd_set_auto_state(false);
            // auto_state = false;
        }
        else
        {
            printf("[set_auto_state] Missing 'onoff' field in 'properties'!\n");
        }
    }
    else
    {
        printf("[set_auto_state] Missing 'properties' field in JSON!\n");
    }
}

void tcp_receive_data(void)
{
    cJSON *root = NULL;
    cJSON *cmd_name = NULL;
    char *cmd_name_str = NULL;
    char buf[BUFF_LEN]; // 接收缓冲区
    int buf_len = 0;
    int count;
    while (1)
    {
        count = recv(client_fd, buf, BUFF_LEN, 0); // read是阻塞函数，没有数据就一直阻塞
        // count = lwip_read(client_fd, buf, BUFF_LEN);  //read是阻塞函数，没有数据就一直阻塞
        if (count == -1)
        {
            printf("[tcp_receive_data] recieve data fail!\n");
            LOS_Msleep(3000);
            break;
        }
        printf("[tcp_receive_data] rev client msg:%s\n", buf);
        buf_len = strlen(buf);
        root = cJSON_ParseWithLength(buf, buf_len);
        if (root != NULL)
        {
            cmd_name = cJSON_GetObjectItem(root, "command_name");
            if (cmd_name != NULL)
            {
                cmd_name_str = cJSON_GetStringValue(cmd_name);
                if (!strcmp(cmd_name_str, "light_control"))
                {
                    printf("command_name is light_control");
                    set_light_state(root);
                }
                else if (!strcmp(cmd_name_str, "motor_control"))
                {
                    printf("command_name is motor_control");
                    set_motor_state(root);
                }
                else if (!strcmp(cmd_name_str, "auto_control"))
                {
                    printf("command_name is auto_control");
                    set_auto_state(root);
                }
                else
                {
                    printf("[tcp_receive_data] unknown command: %s\n", cmd_name_str);
                }
            }
        }
        else
        {
            printf("[tcp_receive_data] command_name not found in JSON!\n");
        }
        cJSON_Delete(root);
    }
    lwip_close(client_fd);
}

unsigned int tcp_is_connected(void)
{
    return tcp_ConnectFlag;
}
